﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IWMAG.Scripting.AST.ObjectModel;
using IWMAG.Scripting.Types;
using IWMAG.Scripting.Compiler;
using System.Reflection;
using IWMAG.Scripting.Interpreter;

namespace IWMAG.Scripting.AST.Operators {
    public class NewOperator : CodeExpression {
        public CodeType Type;
        public List<CodeExpression> Arguments = new List<CodeExpression>();
        protected ConstructorInfo Constructor;

        public NewOperator(Lexeme l, CodeType t) : base(l) {
            Type = t;
        }

        public override void Verify(Helpers.CompileTable sym, List<IUserInfo> error) {
            Type = sym.Dealias(Type);
            Type t = Marshaller.Marshal(Type, sym);

            Type[] paramtype = new Type[Arguments.Count];

            for (int i = 0; i < Arguments.Count; i++) {
                Arguments[i].Verify(sym, error);
                paramtype[i] = Marshaller.Marshal(Arguments[i].TypeOf(), sym);
            }

            Constructor = t.GetConstructor(paramtype);

            if (Constructor == null) {
                SendError(error, "No constructor exists for " + Type.ToString() + " takes the given arguments");
                return;
            }
        }

        public override CodeType TypeOf() {
            return Type;
        }

        public override IEnumerable<Continuation> ValueOf(Interpreter.ScriptEngine engine, Helpers.RuntimeTable sym, Interpreter.Reference<Interpreter.RunValue> val) {
            object[] args = new object[Arguments.Count];

            int i = 0;
            foreach (CodeExpression expr in Arguments) {
                Reference<RunValue> arg = RunValue.NoValue;
                foreach (Continuation wait in expr.ValueOf(engine, sym, arg)) yield return wait;
                args[i++] = arg.ReferencedValue.Value;
            }

            engine.IsExterned = true;
            val.ReferencedValue.Value = Constructor.Invoke(args);
            engine.IsExterned = false;
            yield break;
        }
    }
}
